#!/usr/bin/env python
# _*_coding:utf-8_*_
# 作者：王永存
# python3.5.1 on windows 10 test OK
import sqlite3
import getpass
import sys
import datetime
import os
class Database(object):  # 创建一个关于数据库的类
	def __init__(self,dbname):
		self.dbname = dbname
		self.conn = sqlite3.connect(dbname)
		self.cursor = self.conn.cursor()
	# 查询语句
	def query_user(self,name): 
		self.cursor.execute("select * from user where name='%s';" % name)
		user_message = self.cursor.fetchall()
		if len(user_message) == 0:
			return False
		else:	# [('id', 'name', 'passwd', 'false_num', 'money', 'last_login')]
			self.name = user_message[0][1]
			self.passwd = user_message[0][2]
			self.false_num = user_message[0][3]
			self.money = user_message[0][4]
			self.last_login = user_message[0][5]
	# 更新语句
	def update_db(self,update_data,value):
		self.cursor.execute(update_data, value)
		self.conn.commit()
	# 插入语句
	def insert_db(self,insert_data,value):
		self.cursor.execute(insert_data,value)
		self.conn.commit()
	# 列表获取
	def query_list(self,type_num,owner_num=0):
		self.cursor.execute("select * from shop where type='%s' and owner='%s';" % (type_num ,owner_num))
		shop_list = self.cursor.fetchall()
		return shop_list
	# 关闭数据库
	def close(self):
		self.cursor.close()
		self.conn.close()

def login_show(user_choice):  # 登陆界面的登陆选择判断
	if  0 < user_choice <= 4: # 正确的序号判断
		if user_choice == 1:  # 用户选择为1.用户登陆
			flag = True
			while flag: # 用户输入账号密码循环，如果正确则进入商城系统并返回当前登入系统的用户名字
				username = input('请输入用户名: ').strip()
				passwd = getpass.getpass('请输入密码: ')
				if login(username, passwd) == True: # 账号密码匹配判断，正确or错误
					flag = False
				else:
					flag = True
			return username   # 用户登陆成功返回登陆成功的用户名字
		elif user_choice == 2:  # 用户选择2.注册用户
			flag = True
			while flag:
				username = input('请输入用户名: ').strip() # 获取需要注册用户名
				passwd = getpass.getpass('请输入密码: ')  # 获取注册用户的原密码
				passwd_check = getpass.getpass('请再次输入密码: ')  # 获取注册用户的原密码
				if passwd == passwd_check:
					money = int(input('输入充值金额: ').strip())  # 获取注册用户的充值金额
					if user_register(username,passwd,money) == True: # 注册成功返回True
						flag = False
						sys.exit("注册成功，稍后退出，请重新登陆")  # 注册成功后，需要退出程序，重新登陆
					else:
						print("用户名已存在，请重新注册") # 如果注册用户名已经存在，则重新循环输入
						flag = True
				else:
					choice = input("两次密码输入不一致，按q退出，其他任意键重新输入: ").strip() # 判断输入
					if choice == 'q':
						sys.exit("期待您的下次光临~！")
					else:
						continue					
		elif user_choice == 3: # 用户选择为3.修改密码
			flag = True
			while flag: # 用户修改米吗循环
				username = input('请输入用户名: ').strip()
				passwd = getpass.getpass('请输入原始密码: ')
				if login(username,passwd) == True: # 需要修改的用户密码判断
					new_passwd = getpass.getpass('请输入新的登陆密码: ') # 获取新的密码
					new_passwd_check = getpass.getpass('请再次输入新的登陆密码: ') # 重复检查确认新的密码
					if new_passwd == new_passwd_check:  # 两次修改的密码一致性确认
						db = Database('shop.db') # 实例化Database类
						update_data = 'update user set passwd=? where name=?'
						value = (new_passwd_check, username)
						db.update_db(update_data,value) # 更新数据库中的用户名与密码
						db.close() # 关闭数据库
						sys.exit("用户密码修改成功,请使用新密码重新登陆！") # 修改成功后退出，重新登陆
					else:
						choice = input("两次密码输入不一致，按q退出，其他任意键重新输入: ").strip() # 判断输入
						if choice == 'q':
							sys.exit("期待您的下次光临~！")
						else:
							continue
				else:
					print("账号与密码不匹配") 
					flag = False
		elif user_choice == 4:
			sys.exit("期待您的下次光临~！")

def login(username,passwd):  # 登陆函数
	db = Database('shop.db')  # 实例化Database类
	if db.query_user(username) == False:  # 用户判断
		sys.exit("用户不存在，请先注册，程序退出...")		
	if db.false_num < 3:  # 用户锁定判断，锁定数值大于3 将被禁止登陆
		if db.passwd == passwd:  # 用户验证通过
			print("欢迎 %s 登陆超级商城！账户余额：%s, 上次登陆时间为：%s" % (db.name,db.money,db.last_login))
			now_time = datetime.datetime.now()
			current_time = now_time.strftime("%Y-%m-%d %H:%M:%S")
			update_data = 'update user set last_login =? where name=?'
			value = (current_time, db.name)
			db.update_db(update_data,value)  # 更新用户最后一次登陆时间
			return True
		else:
			update_num = db.false_num + 1 # 用户密码输入错误后，用户锁定值 + 1
			num = 3 - update_num
			update_data = 'update user set false_num=? where name=?'
			value = (update_num, db.name)
			db.update_db(update_data,value)
			print("用户名与密码不匹配，3次输入错误将锁定用户, %s用户今天还有%s 次机会。" % (db.name, num))
			choice = input("按q退出，任意键继续输入：").strip()
			if choice == 'q':
				sys.exit("欢迎下次登录~！")
	else:	
		sys.exit("用户已经被锁定，禁止登陆，请联系管理员！")  # 用户锁定值大于3将被锁定
	db.close()

def user_register(username,passwd,money):  # 用户注册函数
	db = Database('shop.db')
	if db.query_user(username) == False: # 判断要注册的用户是否已经存在
		name = username
		password = passwd
		money = int(money)
		now_time = datetime.datetime.now()
		time = now_time.strftime("%Y-%m-%d %H:%M:%S") # 用户的注册时间
		insert_data = "insert into user (name,passwd,false_num,money,last_login) values(?,?,?,?,?)"
		value = (name, passwd, 0, money, time)
		db.insert_db(insert_data,value) # 向数据户插入一条数据信息
		return True
	else:  
		return False 
	db.close()

def show_list(type_num, owner_num=0, num=0): # 列表展示函数
	db = Database('shop.db')
	list_tmp = db.query_list(type_num, owner_num)
	# [(id, product, price, type, owner)] # 获取的列表模型
	for index,item in enumerate(list_tmp):
		if item[2] == 0:
			print('\t',index+1, item[1]) # 第一层分类列表
		else:
			print('\t',index+1, item[1], '\t',item[2],'元')  # 第二层商品列表
	db.close()
	return list_tmp  # 函数返回一个列表

def recharge(username,money):  # 充值函数，给username 充money
	db = Database('shop.db')
	db.query_user(username)
	update_data = "update user set money=? where name=?"
	update_money = db.money + int(money)
	value = (update_money, username)
	db.update_db(update_data,value)
	db.query_user(username)
	print("用户%s 充值成功，充值金额%s, 账户余额为%sRMB" % (username,money,db.money))
	db.close()

def get_buy_product(list_name,product_num,buy_num):	 # 获取购买物品的信息
	product_name = str(list_name[int(product_num) -1][1])
	product_price = list_name[int(product_num) -1][2]
	product_num = int(buy_num)
	item_dict = {product_name:[product_price,product_num]}
	product_list = [product_name, item_dict]
	return product_list # 返回的物品列表

def show_shopping_cart(shopping_cart): # 购物车展示函数
	print('---------------------------------------------------------------')
	print('---------------------购物车中的商品----------------------------')
	print('%-5s %-15s %-15s %-10s %-20s' % ('ID', 'Name', 'Price', 'Num','Total' ))
	total_price = 0
	i = 0
	for key,val in shopping_cart.items():
	    product_name = key
	    product_price = val[0]
	    product_num = val[1]
	    total = int(product_price) * int(product_num)
	    total_price = total_price + int(total)
	    i += 1
	    print('%-5d %-15s %-15s %-10s %-20d' % (i, product_name, product_price, product_num, total))	  
	print("购物车中商品总价为:%s元" % total_price)
	print('---------------------------------------------------------------')
	return total_price # 返回总价

def edit_shopping_cart(shopping_cart): # shopping_cart= {'book':[111,2], 'ipad':[1234,1]} 修改购物车
    edit_cart = shopping_cart # 定义一个待编辑的购物车，内容与购物车中一样
    if len(edit_cart) == 0: # 如果购物为空即没有购买项，则提示退出
    	print("购物车里没有商品无法修改！")
    	return  edit_cart
    else:  # 购物车不为空执行以下
	    flag = True
	    while flag:
	        i = 0
	        item_list = sorted(edit_cart)  # 将购物车的字典变成有序列表
	        print('\n---------------------购物车中的商品----------------------------')
	        print('%-5s %-15s %-15s %-10s %-20s' % ('ID', 'Name', 'Price', 'Num','Total' ))
	        print('---------------------------------------------------------------')
	        for item in item_list:
	            i += 1
	            product_price = shopping_cart[item][0]
	            product_num = shopping_cart[item][1]
	            total_price = int(product_price) * int(product_num)
	            print('%-5d %-15s %-15s %-10s %-20d' % (i, item, product_price, product_num, total_price))
	            print('---------------------------------------------------------------')
	        choice = input("输入要修改商品的id： ").strip() # 用户选择要修改的商品编号
	        if choice.isdigit() and 0 < int(choice) <= len(sorted(item_list)): # 判断输入商品编号的有效性
	            product_name = item_list[int(choice) - 1]
	            choice_num = input("输入要修改的数量：").strip()  # 用户选择要修改的数量
	            if choice_num.isdigit() and  0 < int(choice_num):  # 修改商品数量
	                edit_cart[product_name][1] = int(choice_num)
	                print("修改完成")
	                break
	            elif choice_num.isdigit() and int(choice_num) == 0: # 如果修改成0，则直接删除该商品
	                del edit_cart[product_name]
	                print("修改完成")
	                break
	            else:
	                print("请输入正确的数量")  # 输入有效的编号
	        else:
	            print("请输入正确的商品序号")
	    return  edit_cart # 函数最后返回编辑后的购物车内容

def settlement(cart_list,username): # 结算支付函数
	flag = True
	while flag:
		db = Database('shop.db')
		db.query_user(username)
		current_money = db.money	
		total = int(show_shopping_cart(cart_list)) # 购物车中商品总价
		print("账号余额:%s, 商品总价:%s" % (current_money, total))
		if current_money < total:  # 判断账户余额是否充足
			choice = input("账号余额不足，按(r)充值: ")
			if choice == 'r':
				r_money = input("请输入充值金额: ").strip()
				recharge(username,r_money)
				continue
			else:
				flag = False
		else:
			choice = input("账户余额充足，按(y)确认购买,按(q)退出: ") # 如果余额充足，则用户判断是否购买
			if choice == 'y':
				residual_money = current_money - total
				update_data = "update user set money=? where name=?"
				value = (residual_money, username)
				db.update_db(update_data,value)  
				print("购买成功，账户余额: %s"  % residual_money ) # 购买成功
				flag = False
				return True
			elif choice == 'q': # 放弃购买
				flag = False
				return False
		db.close()

def save_record(cart_list,username): # 购物历史保存函数
	# shopping_cart= {'book':[111,2], 'ipad':[1234,1]}
	total_price = 0
	name_list = []
	for key,val in shopping_cart.items(): # 从购物车中获取要保存的购物记录
		product_name = key
		product_price = val[0]
		product_num = val[1]
		total = int(product_price) * int(product_num)
		total_price = total_price + int(total)
		a = product_name + ':' + str(product_num)
		name_list.append(a)
	name = username # 购物者
	now_time = datetime.datetime.now()	
	buy_time = now_time.strftime("%Y-%m-%d %H:%M:%S") # 购买时间
	product_items = ', '.join(name_list) # 购买商品
	total_cost =  total_price # 购买总价格
	db = Database('shop.db')
	insert_data = "insert into history (username,buy_time,product_items,total_price) values(?,?,?,?)"
	value = (username, buy_time, product_items,  total_cost) 
	db.insert_db(insert_data,value) # 插入数据库
	db.close()
	
def show_history(username): # 历史购物查询系统
	db = Database('shop.db')
	db.cursor.execute("select * from history where username='%s';" % username) # 通过数据库过滤出用户的购买记录
	histroy_message = db.cursor.fetchall()
	mes1 = '历史购物记录'
	print(mes1.center(80,'-'))
	print('%-2s %-5s %-10s\t %-10s\t %-40s\t' % ('ID', '用户名', '购买时间', '消费总额(元)','购买内容(商品:数量)' ))
	i = 0
	for item in histroy_message:
		buy_time = item[2]
		buy_items = item[3]
		total_price = item[4]
		i += 1
		print('%-2d %-5s %-10s\t %-10s\t %-40s\t' % (i, username, buy_time, total_price, buy_items)) # 购买记录展示
	mes1 = '数据截止至今'
	print(mes1.center(80,'-'))
	flag = True
	while flag: # 历史记录展示后的用户选择
		choice = input("|q:退出商城|b:继续购物|\n请选择：").strip()
		if choice == 'q':
			sys.exit("欢迎下次光临！")
		elif choice == 'b':
			flag = False			
	db.close()

# 主函数
if __name__ == '__main__':
	if os.path.exists('shop.db') == False:
		sys.exit("缺失数据库文件，程序异常退出")
	login_str = "超级商城登陆系统"	# 登陆流程
	print(login_str.center(50,'*'))  # 显示商城标题
	showlist = [(1,'用户登陆'), (2,'用户注册'), (3,'修改密码'), (4,'退出')] # 登陆选项列表
	flag = True
	while flag:  # 登陆选项判断
		for items in showlist:
			print('\t',items[0],items[1])
		try: # 登陆选项的异常处理
			user_choice = int(input("请选择对应操作的序号: ").strip())
			if user_choice not in [1, 2, 3, 4]:  # 如果选择的登陆选项错误则重新选择
				flag = True
			else:
				login_user_name = (login_show(user_choice))	# 已登录用户名		
				flag = False
		except ValueError: 
			print("请输入正确的序号！")

	# 商城流程
	shopping_cart = {}   # 默认购物车字典
	flag = True
	while flag:  # 商城循环
		welcomt_str = "超级商城商品分类"
		print(welcomt_str.center(50,'*'),'\n')
		show_list(1)   # 第一层列表
		choice_1 = input("\n|q:退出|c:查看购物车|e:修改购物车|h:查看历史购物|\n请输入正确序号选择产品类别：").strip() # owner 第一层列表中的选择
		if choice_1 == 'q':  # 退出商城
			sys.exit("欢迎下次光临~！")
		elif choice_1 == 'h':  # 查看登陆用户的购物记录
			show_history(login_user_name)
			continue
		elif choice_1 == 'c': # 查看购物车
			show_shopping_cart(shopping_cart)
			any_input = input("输入任意键返回购物")
		elif choice_1 == 'e': # 修改购物车
			shopping_cart= edit_shopping_cart(shopping_cart)
			show_shopping_cart(shopping_cart)
			any_input = input("输入任意键返回购物")
		elif choice_1.isdigit() and int(choice_1) in [1, 2, 3]:
			flag = True
			while flag:
				mingxi_str = "超级商城商品明细"  
				print(mingxi_str.center(50,'*'),'\n')
				list_2 = show_list(2,choice_1)  # 第二层列表		
				choice_2 = input("\n|q:退出|p:结算|b:返回|c:查看购物车|e:修改购物车|h:查看历史购物|\n请输入正确序号将序号商品加入购物车：").strip() # 列表的顺序
				if choice_2 == 'b':
					break
				elif choice_2 == 'p':
					if len(shopping_cart) == 0:
						print("购物车中没有商品需要结算，请继续购物。\n")
					else:
						if settlement(shopping_cart,login_user_name)  == True: # 结算购物车判断，是否结算True/False
							save_record(shopping_cart,login_user_name)  # 记录用户购物记录
							shopping_cart.clear() # 付款成功，清空购物车
							break
						else:
							break
				elif choice_2 == 'c':
					show_shopping_cart(shopping_cart)
					any_input = input("输入任意键返回购物")
				elif choice_2 == 'q':
					sys.exit("欢迎下次光临~!")	
				elif choice_2 == 'h':
					show_history(login_user_name)
					continue
				elif choice_2 == 'e': # 修改购物车
					shopping_cart = edit_shopping_cart(shopping_cart) # 返回修改后的购物车，并重新定义购物车内容
					show_shopping_cart(shopping_cart) # 展示修改后的购物车
					any_input = input("输入任意键返回购物")				
				elif choice_2.isdigit() and 0 < int(choice_2) <= len(list_2):
					choice_3 = input("请输入购买数量：").strip()
					if choice_3.isdigit() and 0 < int(choice_3):
						product = get_buy_product(list_2,choice_2,choice_3)[1] # 获取要加入购物车的商品字典{product_name:[price,num]}
						product_name = get_buy_product(list_2,choice_2,choice_3)[0] # 获取商品的名字
						if product_name not in shopping_cart.keys(): # 购买商品不再购物车则直接加入购物车
							shopping_cart.update(product)
						else:  # 购买商品已经在购物车里，则更新购物车里的商品数量
							number = shopping_cart[product_name][1] + int(choice_3) 
							shopping_cart[product_name][1] = number 
						print("成功加入购物车！")
						continue
					else:
						print("温心提示：购买数量至少为1件\n") # 每次输入的购买数量最少为1